using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.GamerServices;
using System.IO;

using System.Reflection;


using CreamX.Framework.GameState.Screens;
using CreamX.Framework.Game.GameEngine;
using CreamX.Framework.GameState;
using CreamX.Framework.Game.Components.GameComponents;
using CreamX.Framework.Attributes;
using CreamX.Framework.Text;
using System.Threading;
using CreamX.Framework.Console;


namespace CreamX.Framework.Game
{
    public class CreamXGame:Microsoft.Xna.Framework.Game
    {
        #region Private Variables
        
        
        public bool DrawGUI = true;
        public GameTime GameTime;
        public static CreamXGame Instance;
        public GraphicsDeviceManager graphics;
        public ContentManager embeddedcontent;
        public ScreenManager screenManager;
        internal Assembly _callingAssembly=null;
        internal List<Assembly> Assemblies = new List<Assembly>();
        
        private CreamXGameEngine _engine;
        private bool _gameactive = false;

        #endregion

        #region Constructor
        public CreamXGame()
        {
            this.Activated += new EventHandler(CreamXGame_Activated);
            this.Deactivated += new EventHandler(CreamXGame_Deactivated);
                
            _callingAssembly = Assembly.GetCallingAssembly();
            LoadAssemblies();    
            graphics = new GraphicsDeviceManager(this);
            //content = new ContentManager(Services);
#if(XBOX)
            embeddedcontent = new ResourceContentManager(Services, XBOXCreamXResources.ResourceManager);
#else
            embeddedcontent = new ResourceContentManager(Services, CreamXResources.ResourceManager);
#endif
            
            Instance = this;
            Components.Add(new FrameRateCounterComponent(this));
            screenManager = new ScreenManager(this);
            Components.Add(screenManager);
            screenManager.AddScreen(new BackgroundScreen());
        }
        #endregion

        private void LoadAssemblies()
        {
            Assembly asm1=Assembly.GetExecutingAssembly();
            string p = Path.GetDirectoryName(Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName);
            foreach (string s in Directory.GetFiles(p))
            {
                try
                {
                    Assembly asm = Assembly.LoadFrom(s);
                    if (HasComponents(asm))
                        Assemblies.Add(asm);
                }
                catch { }
            }
        }

        private bool HasComponents(Assembly asm)
        {
            foreach (Type t in asm.GetTypes())
            {
                if (t.IsDefined(typeof(CreamXComponentAttribute), true))
                {
                    return true;
                }
            }
            return false;
        }
        
        private void SetupEngine()
        {
            _engine = new CreamXGameEngine(graphics.GraphicsDevice);
            _engine._manager = graphics;
            _engine.LoadSettings("creamxsettings.xml");
        }

        private void CreamXGame_Deactivated(object sender, EventArgs e)
        {
            _gameactive = false;
        }

        private void CreamXGame_Activated(object sender, EventArgs e)
        {
            _gameactive = true;
        }

        public bool IsGameActive
        {
            get { return _gameactive; }
        }
        
        public virtual void StartGame()
        {

        }
        
        public void AddMenuItem(Type type,string name)
        {
            MainMenuScreen mnu = (MainMenuScreen)screenManager.GetMainMenuScreen();
            mnu.AddMenuEntry(type,name);
        }
        
        public void AddMenuItem(MenuEntry entry)
        {
            MainMenuScreen mnu = (MainMenuScreen)screenManager.GetMainMenuScreen();
            mnu.AddMenuEntry(entry);
        }
        protected override void Initialize()
        {
            GameConsole.Initialize(this, "Content/FONTS/ArialSmall", Color.White, Color.Black, 0, 7);
            SetupConsole();

            screenManager.SetMainMenuScreen(new MainMenuScreen());
            screenManager.AddScreen(screenManager.GetMainMenuScreen()); 
            base.Initialize();
            StartGame();
            //_mainMenuScreen.AddMenuEntry(null, "Exit");
            graphics.ApplyChanges();


        }

        private void SetupConsole()
        {
            IGameConsole console = (IGameConsole)Services.GetService(typeof(IGameConsole));
            console.Log("Type '?' for help");

            console.BindCommandHandler("?", delegate(GameTime time, string[] args)
            {
                console.Log("Commands");
                console.Log("--------");
                console.Log("PrintArgs [arg1] [arg2] [arg3] ... - Prints the list of arguments passed to it, one per line");
                console.Log("PrintLine [text] - Prints the specified text to the console");
                console.Log("SetDefaultLogLevel [level] - Sets the default log level to the specified level");
                console.Log("SetEchoLogLevel [level] - Sets the log level for echoed output from user input");
                console.Log("SetLogLevelThreshold [threshold] - Sets the log level threshold to the specified threshold value");
                console.Log("SetDisplayLevelThreshold [threshold] - Sets the display level threshold to the specified threshold value");
                console.Log("ToggleEchoEnabled - Toggles the auto input echo feature");
                console.Log("ToggleTimestamp - Toggles the display of each message's timestamp");
                console.Log("ToggleLogLevel - Toggles the display of each message's log level");
                console.Log("SetTextColor [r] [g] [b] - Sets the default text color of console text, where r, g, and b are in the range 0-255");
                console.Log("SetLogLevelColor [level] [r] [g] [b] - Sets the text color for the specified log level, where r, g and b are in the range 0-255");
            });

        }
        protected override void LoadContent()
        {
            SetupEngine();

            
            TextEngine.Instance.Fonts.Add((int)FontNames.Arial, embeddedcontent.Load<SpriteFont>("Arial"));
            TextEngine.Instance.Fonts.Add((int)FontNames.ArialSmall, embeddedcontent.Load<SpriteFont>("ArialSmall"));
            TextEngine.Instance.Fonts.Add((int)FontNames.GameFont, embeddedcontent.Load<SpriteFont>("GameFont"));
            TextEngine.Instance.Fonts.Add((int)FontNames.MenuFont, embeddedcontent.Load<SpriteFont>("MenuFont"));
            //TextEngine.Instance.Fonts.Add((int)FontNames.ChalkBoard, embeddedcontent.Load<SpriteFont>("gamefont"));
            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();
            SaveProfile();
        }
        
        private void SaveProfile()
        {
#if(PROFILE && !XBOX)
            TextWriter __tw = new StreamWriter("RecentProfile.log", false);
            
            __tw.WriteLine();
            __tw.WriteLine();
            __tw.WriteLine();
            __tw.WriteLine("New Profile :" + DateTime.Now.ToString());
            __tw.WriteLine(string.Format("{0,-80}", "(Name),") +
                            string.Format("{0,-30}", "(Avg Time),") +
                            string.Format("{0,-20}", "(Calls),") +
                            string.Format("{0,-20}", "(Max Time),") +
                            string.Format("{0,-20}", "(Total Time),"));
            foreach (Profile __p in CreamXProfiler.Profiles.Values)
            {
                __tw.WriteLine(string.Format("{0,-80}", ((ProfilerName)__p.Name).ToString()+",") +
                            string.Format("{0,-30}", __p.AverageTime + ",") +
                            string.Format("{0,-20}", __p.Calls + ",") +
                            string.Format("{0,-20}", __p.MaxTime + ",") +
                            string.Format("{0,-20}", __p.TotalTime));
            }
            __tw.Close();
             
#endif
        }

        protected override void Update(GameTime gameTime)
        {

            KeyboardState currentKeyboardState = Keyboard.GetState();
#if PROFILE
            if (currentKeyboardState.IsKeyDown(Keys.PageUp))
                Thread.Sleep(1);

            if (currentKeyboardState.IsKeyDown(Keys.PageDown))
                return;
#endif

            CreamXProfiler.StartProfiling(ProfilerName.CreamXUpdate);
            CreamXGameEngine.Instance.GameTime = gameTime;
            base.Update(gameTime);
            CreamXProfiler.StopProfiling(ProfilerName.CreamXUpdate);
        }
        
        protected override void Draw(GameTime gameTime)
        {
            CreamXProfiler.StartProfiling(ProfilerName.CreamXDraw);
            base.Draw(gameTime);
            CreamXProfiler.StopProfiling(ProfilerName.CreamXDraw);
        }
        
        protected void Draw(GameTime gameTime,SpriteBatch __batch)
        {
            GameTime = gameTime;

            CreamXProfiler.StartProfiling(ProfilerName.CreamXDrawObjects);
            foreach (CreamXObject __obj in CreamXGameEngine.Instance.SceneManager.CurrentScene.Objects)
            {
                if (!__obj.Template  && __obj.Visible)
                {
                    __obj.Draw(__batch);
                    
                }
            }
            CreamXProfiler.StopProfiling(ProfilerName.CreamXDrawObjects);
            base.Draw(gameTime);
        }
        
    }
}
